#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (c) 2011 - 2013 Stefano Mazzucco <stefano -at- curso.re>
# All rights reserved.
#
# This file is part of Crystal Ball Plus.
#
# Crystal Ball Plus is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Crystal Ball Plus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Crystal Ball Plus.  If not, see <http://www.gnu.org/licenses/>.

import wx

import sys
import os

import StringIO

from crystalballplus import *

# NOTE:
# Using .GetParent().GetParent()
# because we need to get some attributes from the wx.Frame
# and the ControlPanel is embedded in another wx.Panel
# that is contained in the wx.Frame

class ControlPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        self.d_report = StringIO.StringIO()
        self.a_report = StringIO.StringIO()

        # Open input file/folder
        self.radiolist = ['File', 'Folder']

        self.inp = ''
        self.inpradio = wx.RadioBox(self, -1, '', pos=(-1, -1),
                                    choices=self.radiolist, name="inpRadioBox")
        self.inpselect = self.inpradio.GetSelection()
        self.inpradio.Bind(wx.EVT_RADIOBOX,
                           lambda evt, out='inpselect':
                               self.OnRadioClick(evt, out))
        self.inplabel = wx.TextCtrl(self, value=self.inp, style=wx.TE_READONLY)
        self.inpbtn = wx.Button(self, label="Select Input")
        self.inpbtn.Bind(wx.EVT_BUTTON,
                         lambda evt, lbl=self.inplabel,
                         select='inpselect', out='inp':
                             self.OnBtn(evt, lbl, select, out))
        # Open reference file/folder
        self.ref = ''
        self.refradio = wx.RadioBox(self, -1, '', pos=(-1, -1),
                                    choices=self.radiolist, name="refRadioBox")
        self.refselect = self.refradio.GetSelection()
        self.refradio.Bind(wx.EVT_RADIOBOX,
                           lambda evt, out='refselect':
                               self.OnRadioClick(evt, out))
        self.reflabel = wx.TextCtrl(self, value=self.ref, style=wx.TE_READONLY)
        self.refbtn = wx.Button(self, label="Select Reference")
        self.refbtn.Bind(wx.EVT_BUTTON,
                         lambda evt, lbl=self.reflabel,
                         select='refselect', out='ref':
                             self.OnBtn(evt, lbl, select, out))


        self.progrange = 1000
        self.progbar = wx.Gauge(parent=self, range=self.progrange,
                                pos=(175, 120), size=(200, 15))
        self.startbtn = wx.Button(self, label="START")
        self.startbtn.Bind(wx.EVT_BUTTON, self.OnStart)

        # BOX SIZERS
        self.mainbox = wx.BoxSizer(wx.VERTICAL)
        # input
        self.inpbox = wx.BoxSizer(wx.HORIZONTAL)
        self.inpbox.Add(self.inpradio, 1, wx.EXPAND)
        self.inpbox.Add(self.inpbtn, 1, wx.EXPAND)
        self.inpbox2 = wx.BoxSizer(wx.HORIZONTAL)
        self.inpbox2.Add(self.inplabel, 3, wx.EXPAND)
        # reference
        self.refbox = wx.BoxSizer(wx.HORIZONTAL)
        self.refbox.Add(self.refradio, 1, wx.EXPAND)
        self.refbox.Add(self.refbtn, 1, wx.EXPAND)
        self.refbox2 = wx.BoxSizer(wx.HORIZONTAL)
        self.refbox2.Add(self.reflabel, 3, wx.EXPAND)
        # start box
        self.startbox = wx.BoxSizer(wx.HORIZONTAL)
        self.startbox.Add(self.startbtn, 0, wx.ALIGN_CENTER)
        # main box
        self.mainbox.Add(self.inpbox, 0, wx.EXPAND)
        self.mainbox.Add(self.inpbox2, 0, wx.EXPAND)
        self.mainbox.Add(self.refbox, 0, wx.EXPAND)
        self.mainbox.Add(self.refbox2, 0, wx.EXPAND)
        self.mainbox.Add(self.progbar, 0, wx.EXPAND)
        self.mainbox.Add(self.startbox, 0, wx.ALIGN_CENTER)
        self.SetSizer(self.mainbox)

        self.SetAutoLayout(True)
        self.mainbox.Fit(self)

        self.Show(True)         # finally, show the frame

    def OnRadioClick(self, evt, out):
        """Choose file or folder.
        A lambda should be used to bind this method.

        """
        self.GetParent().GetParent().SetStatusText(self.GetParent().GetParent().startmsg)
        radiobox = evt.GetEventObject()
        radioidx = radiobox.GetSelection()
        self.__setattr__(out, radioidx)

    def OnBtn(self, evt, label, select, out):
        """Load the selected file/folder.
        A lambda should be used to bind this method.

        """
        self.GetParent().GetParent().SetStatusText(self.GetParent().GetParent().startmsg)
        s = self.__getattribute__(select)
        fname = ''
        if s == 0: # select file
            msg = "Choose file"
            dlg = wx.FileDialog(self, msg, out, '',
                                'DFG files (*.dfg)|*.dfg|All files (*.*)|*.*',
                                style=wx.FD_FILE_MUST_EXIST)
            if dlg.ShowModal() == wx.ID_OK:
                fname = dlg.GetFilename()
                dirname = dlg.GetDirectory()
                fname = os.path.join(dirname, fname)
        elif s == 1:
            msg = "Choose folder"
            dlg = wx.DirDialog(self, msg, '', wx.DD_DIR_MUST_EXIST)
            if dlg.ShowModal() == wx.ID_OK:
                fname = dlg.GetPath()
        self.__setattr__(out, fname)
        label.SetValue(os.path.basename(fname))

    def OnSaveBtn(self, evt, label, out):
        """Save the reports.
        A lambda should be used to bind this method.

        """
        self.GetParent().GetParent().SetStatusText(self.GetParent().GetParent().startmsg)
        fname = ''
        msg = "Save file"
        dlg = wx.FileDialog(self, msg, out, '',
                            'All files (*.*)|*.*',
                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
        if dlg.ShowModal() == wx.ID_OK:
            fname = dlg.GetFilename()
            dirname = dlg.GetDirectory()
            fname = os.path.join(dirname, fname)
        self.__setattr__(out, fname)
        label.SetValue(os.path.basename(fname))

    def OnStart(self, evt):
        """Start the data analysis

        """

        self.d_report.truncate(0)
        self.a_report.truncate(0)

        # homedir is os.environ['HOME']
        d = 'Comparing d-spacings'
        drep = 'Generating d-spacings report'
        r = 'Grouping reflections'
        a = 'Comparing angles (please wait)'
        arep = 'Generating angles report'
        fail = 'Failed'
        good = 'Succeeded'

        if not self.inp:
            dlg = wx.MessageDialog(self, 'Input data is not set.',
                                   style=wx.OK)
            val = dlg.ShowModal()
            dlg.Destroy()
            return

        if not self.ref:
            dlg = wx.MessageDialog(self, 'Reference data is not set.',
                                   style=wx.OK)
            val = dlg.ShowModal()
            dlg.Destroy()

            return

        if self.GetParent().GetParent().nomatch == 'True':
            nomatch = True
        elif self.GetParent().GetParent().nomatch == 'False':
            nomatch = False
        else:
            dlg = wx.MessageDialog(self, 'Error setting "nomatch" parameter.',
                                   style=wx.OK)
            val = dlg.ShowModal()
            dlg.Destroy()
            return

        self.progbar.SetValue(pos=0)
        step = self.progrange / 5

        # COMPARE D-SPACINGS
        self.GetParent().GetParent().SetStatusText(d)
        try:
            self.progbar.SetValue(pos=self.progbar.GetValue() + step)
            minerr_d = float(self.GetParent().GetParent().minerr_d) / 100
            D = compare_d(self.inp, self.ref, minerr=minerr_d)
            self.GetParent().GetParent().SetStatusText(d + ': ' + good)
        except:
            print('ERROR: ' + str(sys.exc_info()[1]))
            self.GetParent().GetParent().SetStatusText(d + ': ' + fail)
            print(d + ': ' + fail)
            return

        # GENERATE D-SPACINGS REPORT
        self.GetParent().GetParent().SetStatusText(drep)
        self.GetParent().GetParent().dpanel.logger.Clear()
        try:
            gen_d_report(D, self.d_report, nomatch=nomatch)
            self.GetParent().GetParent().dpanel.logger.AppendText(self.d_report.getvalue())
            self.GetParent().GetParent().SetStatusText(drep + ': ' + good)
            self.progbar.SetValue(pos=self.progbar.GetValue() + step)
        except:
            sys.stderr.write('ERROR: ' + str(sys.exc_info()[1]) + '\n')
            self.GetParent().GetParent().SetStatusText(drep + ': ' + fail)
            print(drep + ': ' + fail)
            return

        # GROUP REFLECTIONS
        self.GetParent().GetParent().SetStatusText(r)
        try:
            R = group_reflections(D)
            self.GetParent().GetParent().SetStatusText(r + ': ' + good)
            self.progbar.SetValue(pos=self.progbar.GetValue() + step)
        except:
            print('ERROR: ' + str(sys.exc_info()[1]))
            self.GetParent().GetParent().SetStatusText(r + ': ' + fail)
            print(r + ': ' + fail)
            return

        # COMPARE ANGLES
        self.GetParent().GetParent().SetStatusText(a)
        try:
            minerr_a = float(self.GetParent().GetParent().minerr_a) / 100
            A = compare_angles(R, minerr=minerr_a, check=self.GetParent().GetParent().check)
            self.GetParent().GetParent().SetStatusText(a + ': ' + good)
            self.progbar.SetValue(pos=self.progbar.GetValue() + step)
        except:
            print('ERROR: ' + str(sys.exc_info()[1]))
            self.GetParent().GetParent().SetStatusText(a + ': ' + fail)
            print(a + ': ' + fail)
            return

        # GENERATE ANGLE REPORT
        self.GetParent().GetParent().SetStatusText(arep)
        self.GetParent().GetParent().apanel.logger.Clear()
        try:
            gen_angle_report(A, self.a_report, nomatch=nomatch)
            self.GetParent().GetParent().apanel.logger.AppendText(self.a_report.getvalue())
            self.GetParent().GetParent().SetStatusText(arep + ': ' + good)
            self.progbar.SetValue(pos=self.progbar.GetValue() + step)
        except:
            print('ERROR: ' + str(sys.exc_info()[1]))
            self.GetParent().GetParent().SetStatusText(arep + ': ' + fail)
            print(arep + ': ' + fail)
            return
        self.GetParent().GetParent().SetStatusText('Done')


class LogPanel(wx.Panel):
    def __init__(self, parent, id, label):
        wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize,
                          wx.RAISED_BORDER|wx.TAB_TRAVERSAL)

        self.logger = wx.TextCtrl(self, wx.ID_ANY, size=(600,600),
                                  style=wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)

        self.repbtn = wx.Button(self, label=label)
        self.repbtn.Bind(wx.EVT_BUTTON,
                         lambda evt, lbl=label:
                               self.OnSaveBtn(evt, lbl))
        # BOX SIZERS
        self.mainbox = wx.BoxSizer(wx.VERTICAL)
        self.mainbox.Add(self.logger, 0, wx.EXPAND)
        self.mainbox.Add(self.repbtn, 0, wx.EXPAND)
        self.SetSizer(self.mainbox)

        self.SetAutoLayout(True)
        self.mainbox.Fit(self)

        self.Show(True)         # finally, show the frame

    def OnSaveBtn(self, evt, label):
        """Save the reports.
        A lambda should be used to bind this method.

        """
        fname = ''
        msg = "Save report"
        dlg = wx.FileDialog(self, msg, '', '',
                            'All files (*)|*',
                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
        if dlg.ShowModal() == wx.ID_OK:
            fname = dlg.GetFilename()
            dirname = dlg.GetDirectory()
            fname = os.path.join(dirname, fname)
            self.logger.SaveFile(fname)
